#encoding=utf8
'''
Created on Sep 12, 2014

@author: jingyang <jingyang@smalltreemedia.com>
'''
from functools import partial

from django.contrib import admin
from django.utils import timezone
from django.contrib import messages
from django.core.exceptions import PermissionDenied
from django.forms.models import modelformset_factory
from django.shortcuts import get_object_or_404
from django.contrib.auth.models import User, Group

import gspread
from gspread.exceptions import CellNotFound

import settings
from app_info.models import App, Studio, StudioCloud, UserGroup, AppExtraInfo,\
    AppVersion, AppleID, FlurryKey, ProductionTeam, APP_STORE, PRODUCTION_STATUS,\
    GAKey, QuantCastKey, CompanyGroup, Company
from app_info.forms import AppForm, StudioCloudForm, StudioAdminForm,\
    AppVersionForm, CustomGroupForm, CustomUserGroupForm, ProductionTeamForm, CompanyForm
from utils import field, email_sending, api_call
from threads import UpdateGoogleSheetThread
from django.contrib.auth.admin import GroupAdmin, UserAdmin
from notification.models import Notice
import json
from django.core.mail import mail_admins
from django.contrib.admin.filters import SimpleListFilter
from django.db import models, transaction
from sub_info.models import SubInfo

from django.views.decorators.csrf import csrf_protect
from django.utils.decorators import method_decorator


csrf_protect_m = method_decorator(csrf_protect)


class StudioCloudAdmin(admin.ModelAdmin):
    list_display = ('cloud_id', 'get_cloud_purpose', 'get_studios_count',
                    'get_parent_brand', 'get_studios',
                    'get_app_code_ios', 'get_app_code_gp', 'get_app_code_amz')
    form = StudioCloudForm
    list_per_page = 20

    class Media:
        js = ('admin/js/SelectBox.js', 'base/js/SelectFilter2.js',
              'base/js/custom_studio_cloud_admin.js')

    @field('App Code (iOS)', allow_tags=True)
    def get_app_code_ios(self, obj):
        code_list = ['%s - %s' % (id, code or '') for id, code in
            obj.studio_set.values_list('custom_id', 'ios_code_format')]
        return '<br />'.join(code_list)

    @field('App Code (GP)', allow_tags=True)
    def get_app_code_gp(self, obj):
        code_list = ['%s - %s' % (id, code or '') for id, code in
            obj.studio_set.values_list('custom_id', 'gp_code_format')]
        return '<br />'.join(code_list)

    @field('App Code (Amz)', allow_tags=True)
    def get_app_code_amz(self, obj):
        code_list = ['%s - %s' % (id, code or '') for id, code in
            obj.studio_set.values_list('custom_id', 'amz_code_format')]
        return '<br />'.join(code_list)

    @field("Cloud Purpose", allow_tags=True)
    def get_cloud_purpose(self, obj):
        return obj.cloud_purpose

    @field("Number of Studios", admin_order_field='studio__count')
    def get_studios_count(self, obj):
        return obj.studio__count

    @field("Studios Included", allow_tags=True)
    def get_studios(self, obj):
        return "<br />".join([s.__unicode__() for s in obj.studio_set.all()])

    @field("Parent Brand")
    def get_parent_brand(self, obj):
        try:
            return Studio.objects.get(id=obj.parent_brand)
        except:
            return ''

    # inspired with http://stackoverflow.com/questions/2168475/django-admin-how-to-sort-by-one-of-the-custom-list-display-fields-that-has-no-d
    def queryset(self, request):
        qs = admin.ModelAdmin.queryset(self, request)
        qs = qs.annotate(models.Count('studio'))
        return qs

    def save_model(self, request, obj, form, change):
        obj.save()
        obj.studio_set.all().update(cloud=None)
        for s in obj.studios:
            s.cloud = obj
            s.save()

    def get_actions(self, request):
        """
        remove delete action
        """
        actions = super(StudioCloudAdmin, self).get_actions(request)
        if actions.get('delete_selected'):
            del actions['delete_selected']
        return actions

    @csrf_protect_m
    @transaction.commit_on_success
    def change_view(self, request, object_id, form_url='', extra_context=None):
        user = request.user
        if user.groups.filter(name='Management').exists() and not user.is_superuser:
            raise PermissionDenied
        return admin.ModelAdmin.change_view(self, request, object_id, form_url=form_url, extra_context=extra_context)


class AppStoreListFilter(SimpleListFilter):
    title = 'Available Store'
    parameter_name = 'store'

    def lookups(self, request, model_admin):
        return APP_STORE

    def queryset(self, request, queryset):
        if self.value():
            return queryset.filter(available_store__contains=self.value())
        return queryset


class StudioAdmin(admin.ModelAdmin):
    search_fields = ('prd_name', 'pub_name', 'studio_code', 'bundle_id', 'custom_id')
    list_display = ('custom_id', 'pub_name', 'prd_name', 'get_ios_code_format',
        'get_gp_code_format', 'get_amz_code_format', 'get_bundle_id_prefix',
        'code', 'cloud', 'get_stores')
    list_display_links = ('pub_name',)
#    exclude = ('cloud', 'app_store_id', 'service_site')
    list_filter = (AppStoreListFilter,)
    list_per_page = 20
    form = StudioAdminForm
    readonly_fields = ('studio_code', 'prd_name', 'pub_name', 'copy_right', 'main_domain',
                       'alt_domain', 'bundle_id', 'get_bundle_id_prefix', 'available_store', 'get_stores',
                       'production_location_assignment')
    fieldsets = (
        ('General Info (Synchronized with Publish Service System)',
            {'fields':
                (
                 'studio_code',
                 'pub_name',
                 'prd_name',
                 'copy_right',
                 'main_domain',
                 'alt_domain',
                 'get_bundle_id_prefix',
                 'get_stores',
                 'production_location_assignment'
                )
            }),
        ('Advanced Info',
            {'fields':
                (
                 'custom_id',
                 'website',
                 'ios_code_format',
                 'gp_code_format',
                 'amz_code_format',
                 'code',
                )
             }),
    )

    @field("App Store Availability", allow_tags=True, admin_order_field='available_store')
    def get_stores(self, obj):
        stores = str(obj.available_store).replace('[', '').replace(']', '').replace("u'", '')\
            .replace("'", '').split(', ')
        for k, v in enumerate(stores):
            if v == 'iTunes App Store':
                stores[k] = "<img src='/static/base/img/app_store.png' width=30 height=30 />"
            elif v == 'Google Play':
                stores[k] = "<img src='/static/base/img/google_play.png' width=30 height=30 />"
            elif v == 'Amazon App Store':
                stores[k] = "<img src='/static/base/img/amz_store.png' width=30 height=30 />"
        return "&nbsp;".join(stores)

    @field("Studio Name (Production)")
    def get_prd_name(self, obj):
        return obj.pub_name

    @field("App Code Format (iOS)")
    def get_ios_code_format(self, obj):
        return obj.ios_code_format or ""

    @field("App Code Format (GP)")
    def get_gp_code_format(self, obj):
        return obj.gp_code_format or ""

    @field("App Code Format (Amz)")
    def get_amz_code_format(self, obj):
        return obj.amz_code_format or ""

    @field("Studio Publish Name (Production Name)")
    def get_studio_name(self, obj):
        return obj.__unicode__()

    @field("Bundle ID Prefix", allow_tags=True)
    def get_bundle_id_prefix(self, obj):
        return "<br />".join(obj.bundle_id.splitlines())

    def get_actions(self, request):
        """
        remove delete action
        """
        actions = super(StudioAdmin, self).get_actions(request)
        if actions.get('delete_selected'):
            del actions['delete_selected']
        return actions

    @csrf_protect_m
    @transaction.commit_on_success
    def change_view(self, request, object_id, form_url='', extra_context=None):
        user = request.user
        if user.groups.filter(name='Management').exists() and not user.is_superuser:
            raise PermissionDenied
        return admin.ModelAdmin.change_view(self, request, object_id, form_url=form_url, extra_context=extra_context)


class AppVersionInline(admin.StackedInline):
    model = AppVersion
    can_delete = False
    suit_classes = 'suit-tab suit-tab-version'
#    exclude = ('create_time',)
    form = AppVersionForm
    extra = 1
    readonly_fields = ('editor', 'type', 'create_time', 'get_editor',
        'date_released', 'code_dir')
    fieldsets = (
        (None, {
            'fields':
            (
            'get_editor',
            'create_time',
            'code',
            'type',
            'purpose',
            'change_list',
            'iap_required',
            'ads_required',
            'cross_promo_required',
            'product_owner',
            'owner',
            'prd_team',
            'programmer',
            'ref_id',
            'link_of_product_brief',
            'status',
            'date_released',
            'code_dir',
            'sdk_required'
            )
        }),
    )

    class Media:
        js = ('base/js/collapsed_stacked_inlines.js',)

    @field('Create By')
    def get_editor(self, obj):
        return obj.editor.split('@')[0]

    def get_readonly_fields(self, request, obj=None):
        if not request.user.is_superuser and\
        not request.user.groups.filter(name='Post-production Staff').exists():
            return ('editor', 'type', 'status', 'create_time', 'get_editor')
        return admin.StackedInline.get_readonly_fields(self, request, obj=obj)

    def get_formset(self, request, obj=None, **kwargs):
        if obj.appversion_set.exists():
            self.extra = 0
        return admin.StackedInline.get_formset(self, request, obj=obj, **kwargs)

    def queryset(self, request):
        queryset = admin.StackedInline.queryset(self, request)
        queryset = queryset.order_by('-code')
        return queryset


class AppStatusListFilter(SimpleListFilter):
    title = 'App Status'
    parameter_name = 'aps'

    def lookups(self, request, model_admin):
        return PRODUCTION_STATUS

    def queryset(self, request, queryset):
        if self.value():
            app_list = AppVersion.objects.filter(code='1.0', status=self.value())\
                .values_list('app', flat=True)
            return queryset.filter(id__in=app_list)
        return queryset


class AppAdmin(admin.ModelAdmin):
    list_display = ('prd_id', 'prj_code', 'get_app_name', 'studio',
                    'get_editor_name', 'get_platform', 'get_status',
                    'get_apple_id_ready', 'get_pub_key_ready', 'get_ads_req_status',
                    'get_iap_req_status', 'get_flurry_req_status', 'get_ga_req_status', 'get_quantcast_req_status',
                    'get_v1_status')
#    list_editable = ('status', 'notes', 'app_id')
    list_filter = ('studio', 'status', 'platform', 'editor', 'app_store', AppStatusListFilter)
    save_on_top = True
    search_fields = ('prj_code', 'app_name', 'bundle_id_suffix', 'app_id', 'editor')
    form = AppForm
    list_per_page = 20
    fieldsets = (
        ('Validation', {
            'classes': ('suit-tab', 'suit-tab-basic'),
            'fields':
            (
                'prd_id',
                'company',
                'status',
                'notes',
            )
            }),
        ('Basic', {
            'classes': ('suit-tab', 'suit-tab-basic'),
            'fields':
            (
                'app_store',
                'store_link',
                'platform',
                'studio',
                ('bundle_id_prefix', 'bundle_id_suffix'),
                'prj_code',
                'old_prj_code',
                'app_name',
                'pub_name',
            )
        }),
        ('Extra', {
            'classes': ('suit-tab', 'suit-tab-basic'),
            'fields':
            (
#            'flurry_key',
                'media_local',
                'media_remote',
                'display_name',
#            'special',
#            'cross_local',
#            'cross_remote',
            )
        }),
        (None, {
            'classes': ('suit-tab', 'suit-tab-version',),
            'fields': ()
        })
#        ('Advanced', {
##            'classes': ('collapse',),
#            'fields':
#            (
#            'type',
#            'version',
#            'eta_to_qa',
#            'eta_qa_time',
#            ('fe', 'be'),
#            'ads_type',
#            'kids_cate',
#            'push',
#            'supported_devices',
#            'release_req',
#            'intro'
#            )
#        })
    )

    def _get_log_id(self, v_obj):
        current_year = timezone.now().year
        current_month = timezone.now().month
        current_day = timezone.now().day
        latest = AppVersion.objects.exclude(id=v_obj.pk).filter(create_time__year=current_year,
            create_time__month=current_month, create_time__day=current_day).order_by('-log_id')[:1]
        if latest:
            latest = latest[0]
            num = int(latest.log_id[-3:]) + 1
        else:
            num = 1
        log_id = 'PV%s%s%s%s' % (current_year, '%02i' % current_month,
            '%02i' % current_day, '%03i' % num)
        return log_id

#    def get_list_display(self, request):
#        if not request.user.is_superuser and\
#        not request.user.groups.filter(name='Post-production Staff').exists():
#            return ['get_status' if x == 'status' else x for x in self.list_display]
#        return admin.ModelAdmin.get_list_display(self, request)

    def cancel_sub_info(self, request_id):
        return api_call('%s%s' % (settings.PS_DOMAIN, settings.PS_CANCEL_SUB),
            json.dumps({'request': {'request_id': request_id,
                'status': 'cancel'}}), 'POST', {'Content-Type': 'application/json'})

    def save_formset(self, request, form, formset, change):
        formset.save()
        if formset.model == AppVersion:
            changed_version = formset.save(commit=False)
            for v in changed_version:
                if not v.editor:
                    v.editor = request.user.email
                    v.log_id = self._get_log_id(v)
                    v.save()
                if v.status == 'C':
                    v.get_dev_qa().update(status='X')
                    v.get_release_qa().update(status='X')
                    sub_info = SubInfo.objects.filter(app=v.app, version=v.code)
                    if sub_info.exists():
                        self.cancel_sub_info(sub_info[0].request_id)
                        sub_info.update(validation='C', status='C')

    def get_inline_instances(self, request, obj=None):
        if obj and obj.status == 'V':
            self.inlines = [AppVersionInline]
        else:
            self.inlines = []
        return admin.ModelAdmin.get_inline_instances(self, request, obj=obj)

    def get_fieldsets(self, request, obj=None):
        """
        users can only edit app basic info when add or not valid.
        """
        if not obj:  # when add or not valid
            self.suit_form_tabs = ()
            return ((None, {'fields':
            (
            'company',
            'app_store',
            'platform',
            'studio',
            ('bundle_id_prefix', 'bundle_id_suffix'),
            'prj_code',
            'old_prj_code',
            'app_name',
            'pub_name',
            )
        }),)
        if not get_object_or_404(App, pk=obj.pk).status == 'V':
            self.suit_form_tabs = ()
            return (
            ('Validation', {
            'fields':
            (
            'prd_id',
            'company',
            'status',
            'notes',
            )
            }),
            ('Basic', {'fields':
            (
            'app_store',
            'platform',
            'studio',
            ('bundle_id_prefix', 'bundle_id_suffix'),
            'prj_code',
            'old_prj_code',
            'app_name',
            'pub_name',
            )
        }),)
        self.suit_form_tabs = (('basic', 'App Info'), ('version', 'App Version'))
        if self.declared_fieldsets:
            if obj.platform == 'I':
                self.declared_fieldsets[2][1].update({'fields': (
#                    'flurry_key',
                    'media_local', 'media_remote', 'display_name', 'special')})
            else:
                self.declared_fieldsets[2][1].update({'fields': (
#                    'flurry_key',
                    'media_local', 'media_remote', 'display_name')})
            return self.declared_fieldsets
        form = self.get_form(request, obj)
        fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj))
        return [(None, {'fields': fields})]

    @field('App Name (Production)', allow_tags=True, admin_order_field='app_name')
    def get_app_name(self, obj):
        return "<label title='%s'>%s</label>" % (obj.get_full_bundle_id(), obj.app_name)

    @field('Apple ID Ready?', allow_tags=True)
    def get_apple_id_ready(self, obj):
        if obj.app_store == 'iTunes App Store':
            icon = ('yes', 'True') if obj.app_id else ('no', 'False')
            return "<img src='/static/admin/img/icon-%s.gif' alt='%s'>" % icon
        return ''

    @field('Public Key Ready?', allow_tags=True)
    def get_pub_key_ready(self, obj):
        if obj.app_store == 'Google Play':
            icon = ('yes', 'True') if obj.pub_key else ('no', 'False')
            return "<img src='/static/admin/img/icon-%s.gif' alt='%s'>" % icon
        return ''

    @field('Ads Request & Status', allow_tags=True)
    def get_ads_req_status(self, obj):
        ads = ["<a href='/admin/ads_info/adsinfo/%s/' target='_blank'>%s</a> - %s" %\
               (i.pk, i.request_id, i.get_status_display()) for i in obj.adsinfo_set.all()]
        return "<br />".join(ads)

    @field('IAP Request & Status', allow_tags=True)
    def get_iap_req_status(self, obj):
        iap = ["<a href='/admin/iap_info/iapinfo/%s/' target='_blank'>%s</a> - %s" %\
               (i.pk, i.request_id, i.get_status_display()) for i in obj.iapinfo_set.all()]
        return "<br />".join(iap)

    @field('Flurry Request & Status', allow_tags=True)
    def get_flurry_req_status(self, obj):
        flurry = ["<a href='/admin/app_info/flurrykey/%s/' target='_blank'>%s</a> - %s" %\
                  (i.pk, i.request_id, i.get_status_display()) for i in obj.flurrykey_set.all()]
        return "<br />".join(flurry)

    @field('GA Request & Status', allow_tags=True)
    def get_ga_req_status(self, obj):
        ga = ["<a href='/admin/app_info/gakey/%s/' target='_blank'>%s</a> - %s" %\
              (i.pk, i.request_id, i.get_status_display()) for i in obj.gakey_set.all()]
        return "<br />".join(ga)

    @field('QuantCast Request & Status', allow_tags=True)
    def get_quantcast_req_status(self, obj):
        quantcast = ["<a href='/admin/app_info/quantcastkey/%s/' target='_blank'>%s</a> - %s" %
                     (i.pk, i.request_id, i.get_status_display()) for i in obj.quantcastkey_set.all()]
        return "<br />".join(quantcast)

    @field('App Status', allow_tags=True)
    def get_v1_status(self, obj):
        v1 = obj.appversion_set.filter(code='1.0')
        v1 = v1[0] if v1 else None
        if not v1:
            return ''
        if v1.status == 'I':
            cls = 'label-warning'
        elif v1.status == 'C':
            cls = ''
        elif v1.status == 'S':
            cls = 'label-success'
        elif v1.status == 'L':
            cls = 'label-info'
        elif v1.status == 'O':
            cls = ''
        else:
            cls = 'label-info'
        return "<span class='label %s' style='width:65px;'><center>%s</center></span>" %\
            (cls, v1.get_status_display())

    @field('Validation', allow_tags=True, admin_order_field='status')
    def get_status(self, obj):
        if obj.status == 'P':
            icon = '/static/admin/img/icon-no.gif'
        elif obj.status == 'V':
            icon = '/static/admin/img/icon-yes.gif'
        elif obj.status == 'I':
            icon = '/static/base/img/invalid.png'
        elif obj.status == 'Z':
            icon = '/static/base/img/cancelled.png'
        else:
            icon = None
        return "<center><img src='{0}' alt='{1}' title='{1}' width=10 height=10 /></center>"\
            .format(icon, obj.get_status_display())

    @field('Store Link', allow_tags=True, admin_order_field='app_store')
    def get_store_link(self, obj):
        if obj.status == 'V' and obj.store_link:
            return "<a href='%s' target='_blank'>View on %s</a>" % \
                (obj.store_link, obj.app_store)
        return ''

    @field('Editor', admin_order_field='editor')
    def get_editor_name(self, obj):
        return obj.editor.split("@")[0]

    @field('Platform', allow_tags=True, admin_order_field='platform')
    def get_platform(self, obj):
        rtn = "<a title='view on store' href='%s' target='_blank'>{0}</a>" % obj.store_link if obj.status == 'V' and obj.store_link else ''
        if obj.platform == 'I':
            icon = "<center class='ios'><img src='/static/base/img/ios.png' width=16 height=16 /></center>"
            return rtn.format(icon) if rtn else icon
        elif obj.platform == 'A':
            icon = "<center class='android'><img src='/static/base/img/android.png' width=16 heigth=16 /></center>"
            return rtn.format(icon) if rtn else icon
        else:
            return obj.platform

    class Media:
        js = ('base/js/get_bundle_id_prefix.js',
              'base/js/custom_radio.js',
              'base/js/get_user_company.js',
             )

    def queryset(self, request):
        """
        override the queryset function so that every user only can see the apps
        edited by themselves. Superuser can see all of course.
        """
        qs = self.model._default_manager.get_query_set()
#        user_group = UserGroup.objects.filter(owner=request.user)
#        if request.user.is_superuser:
#            qs = self.model._default_manager.get_query_set()
#        else:
#            if user_group.exists():
##                qs = self.model._default_manager.get_query_set()
#                res = []
#                for g in user_group:
#                    res += [user.email for user in g.user.all()]
#                res += [request.user.email]
#                qs = App.objects.filter(editor__in=list(set(res)))
#            else:
#                qs = App.objects.filter(editor=request.user.email)

        # company filter
        if request.user.is_superuser:
            qs = self.model._default_manager.get_query_set()
        else:
            company = []
            for group in request.user.groups.all():
                if group.permissions.filter(codename__in=['add_app', 'change_app']).exists():
                    company.append(group.companygroup.company.id)
            qs = App.objects.filter(company__in=company)
        # TODO: this should be handled by some parameter to the ChangeList.
        ordering = self.get_ordering(request)
        if ordering:
            qs = qs.order_by(*ordering)
        return qs

    def get_readonly_fields(self, request, obj=None):
        """
        common user can not edit app basic info if it is valid.
        """
        f = ('prd_id',)
        if not obj or (not request.user.is_superuser and not\
            request.user.groups.filter(name='Post-production Staff').exists()):
            f += ('status', 'notes')
        if obj and get_object_or_404(App, pk=obj.pk).status == 'V':
            f += ('prj_code', 'old_prj_code', 'app_name', 'pub_name',
                'studio', 'platform', 'app_store', 'bundle_id_prefix',
                'iap_required', 'ads_required', 'store_link',
                'bundle_id_suffix', 'company')
            return f
        return f

#    def get_changelist_formset(self, request, **kwargs):
#        """
#        Returns a FormSet class for use on the changelist page if list_editable
#        is used.
#        """
#        if not request.user.is_superuser and\
#        not request.user.groups.filter(name='Post-production Staff').exists():
#            list_editable = ()
#        else:
#            list_editable = self.list_editable
#
#        defaults = {
#            "formfield_callback": partial(self.formfield_for_dbfield, request=request),
#        }
#        defaults.update(kwargs)
#        return modelformset_factory(self.model,
#            self.get_changelist_form(request), extra=0,
#            fields=list_editable, **defaults)

#    def response_change(self, request, obj):
#        """
#        always need check if valid after change invalid app
#        """
#        if obj.status == 'I':
#            obj.status = 'P'
#            obj.save()
#        return super(AppAdmin, self).response_change(request, obj)

#    def response_add(self, request, obj, post_url_continue=None):
#        # write data to google sheet. with thread
#        if not settings.DEBUG:
#            if obj.adsrequest_set.count() == 0:
#                UpdateGoogleSheetThread(obj).start()
#            else:
#                UpdateGoogleSheetThread(obj, obj.adsrequest_set.all()[0]).start()
#        return super(AppAdmin, self).response_add(request, obj, post_url_continue=post_url_continue)

    def get_actions(self, request):
        """
        remove delete action
        """
        actions = super(AppAdmin, self).get_actions(request)
        if actions.get('delete_selected'):
            del actions['delete_selected']
        return actions

    def has_delete_permission(self, request, obj=None):
        """
        can not delete valid apps
        """
        if obj and obj.status == 'V':
            return False
        opts = self.opts
        return request.user.has_perm(opts.app_label + '.' + opts.get_delete_permission())

    def save_model(self, request, obj, form, change):
        """
        override the save_model function for saving the object's editor
        """
        if not change:  # add
            latest_app = App.objects.exclude(id=obj.pk).order_by('-prd_id')[:1]
            if latest_app:
                num_app = int(latest_app[0].prd_id[2:]) + 1
            else:
                num_app = 20001
            obj.prd_id = 'CD%s' % num_app
            obj.editor = request.user.email
            obj.save()
            print 'sending to admin a new app'
            Notice.objects.notice_manager('New App Registration Request',
                '''
                <p>A new app registration needs to check:</p>
                <p>App Code: <b>{0}</b></p>
                <p>App Name: <b>{1}</b></p>
                <p>Full Bundle ID: <b>{2}</b></p>
                '''.format(obj.prj_code, obj.app_name.encode('utf8'), obj.get_full_bundle_id()))
#            email_sending(subject='PTS New App Registration Request',
#                          html=settings.EMAIL_HTML_TEMPLATE.format(
#                              'A new app registration needs to check', obj.prj_code,
#                              obj.app_name.encode('utf8'), obj.get_full_bundle_id(), obj.app_id,
#                              obj.notes),
#                          to=[i[1] for i in settings.MANAGERS])
        else:  # change
            if obj.status == 'V':
#                if obj.platform == 'I' and not obj.app_id:  # valid app must have app id
#                    self.message_user(request, 'App ID Required', level=messages.ERROR)
#                    return
                if obj.app_store == 'iTunes App Store':
                    obj.store_link = 'https://itunes.apple.com/app/id%s?mt=8' % obj.app_id if obj.app_id else ""
                elif obj.app_store == 'Google Play':
                    obj.store_link = 'https://play.google.com/store/apps/details?id=%s' % obj.get_full_bundle_id()
                elif obj.app_store == 'Amazon App Store':
                    obj.store_link = 'http://www.amazon.com/gp/mas/dl/android?p=%s' % obj.get_full_bundle_id()
                if not get_object_or_404(App, pk=obj.pk).status == 'V':  # mail the editor
                    if not settings.DEBUG:
                        if not obj.app_id and not obj.pub_key:
                            data = {'request': {'request_created_by': obj.editor,
                                    'app_store': obj.app_store,
                                    'product_id': obj.prd_id,
                                    'app_code': obj.prj_code,
                                    'app_name': obj.app_name,
                                    'primary_language': 'English',
                                    'sku': obj.get_full_bundle_id(),
                                    'bundle_id_prefix': obj.bundle_id_prefix,
                                    'bundle_id_suffix': obj.bundle_id_suffix,
                                    'studio': obj.studio.__unicode__(),
                                    'version': '1.0'}}
                            rtn = api_call('%s%s' % (settings.PS_DOMAIN, settings.PS_CREATE_APP),
                                json.dumps(data), 'POST', {'Content-Type': 'application/json'})
                        else:
                            data = {'request': {'product_id': obj.prd_id, 'app_code': obj.prj_code,
                                'status': 'done'}}
                            rtn = api_call('%s%s' % (settings.PS_DOMAIN, settings.PS_CANCEL_APP),
                                json.dumps(data), 'POST', {'Content-Type': 'application/json'})
                        if not rtn.get('code') == 1:
                            mail_admins('New App Creation Request Sent Failed', rtn.get('msg'))
                            self.message_user(request, 'Server Error', messages.ERROR)
                            return
                    obj.valid_time = timezone.now()
                    obj.valid_person = request.user.email
                    print 'sending email for noticing the app valid...'
                    Notice.objects.send_notice('New App Registration <strong>Done</strong>',
                        '''
                        <p>Your app registration was <strong>successful</strong>:</p>
                        <p>App Code: <b>{0}</b></p>
                        <p>App Name: <b>{1}</b></p>
                        <p>Full Bundle ID: <b>{2}</b></p>
                        <p>Notes: <b>{3}</b></p>
                        '''.format(obj.prj_code, obj.app_name.encode('utf8'), obj.get_full_bundle_id(),
                                   "Next Step - Please fill up extra info of this app."),
                        obj.editor)
#                    email_sending(subject='PTS New App Registration Done',
#                                  html=settings.EMAIL_HTML_TEMPLATE.format(
#                                      'Your app registration was successful.',
#                                      obj.prj_code, obj.app_name.encode('utf8'),
#                                      obj.get_full_bundle_id(), obj.app_id,
#                                      obj.notes + " Next Step - Please fill up extra info of this app."),
#                                  to=[obj.editor])
                    try:
                        owner = User.objects.get(email=obj.editor)
                    except User.DoesNotExist:
                        owner = User.objects.get(email='imported@smalltreemedia.com')
                    v_obj, c = AppVersion.objects.get_or_create(app=obj, code='1.0', type='N',
                        purpose='New App', defaults={'editor': obj.editor, 'owner': owner.pk})
                    if c:
                        v_obj.log_id = self._get_log_id(v_obj)
                        v_obj.save()
                    current_year = timezone.now().year
                    current_month = timezone.now().month
                    current_day = timezone.now().day
                    if not obj.flurry_key:
                        num = FlurryKey.objects.get_latest_num()
                        FlurryKey.objects.get_or_create(app=obj, defaults={'request_id':
                            'RFLU-%s%02i%02i%02i' % (current_year, current_month,
                            current_day, num)})
                    if not obj.ga_key:
                        num2 = GAKey.objects.get_latest_num()
                        GAKey.objects.get_or_create(app=obj,
                                                    defaults={'request_id': 'RGAP-%s%02i%02i%02i' %\
                                                              (current_year, current_month, current_day, num2)})
                    if not obj.quantcast_key:
                        num3 = QuantCastKey.objects.get_latest_num()
                        QuantCastKey.objects.get_or_create(app=obj,
                                                           defaults={'request_id': 'RQUA-%s%02i%02i%02i' %
                                                                                   (current_year, current_month, current_day, num3)})
                    # no longer need make Apple ID request in PTS
#                    if obj.platform == 'I':
#                        num = AppleID.objects.get_latest_num()
#                        AppleID.objects.get_or_create(app=obj, defaults={'request_id':
#                            'RAPP-%s%02i%02i%02i' % (current_year, current_month,
#                            current_day, num)})
                obj.save()
            elif obj.status == 'I':
                if get_object_or_404(App, pk=obj.pk).status == 'I':  # user change info
                    print 'sending email to admin...'
                    Notice.objects.notice_manager('App Registration Updated',
                        '''
                        <p>{0} updated the app, please re-check</p>
                        <p>App Code: <b>{1}</b></p>
                        <p>App Name: <b>{2}</b></p>
                        <p>Full Bundle ID: <b>{3}</b></p>
                        <p>Notes: <b>{4}</b></p>
                        '''.format(obj.editor.split('@')[0], obj.prj_code,
                                   obj.app_name.encode('utf8'), obj.get_full_bundle_id(),
                                   obj.notes))
#                    email_sending(subject='PTS App Registration Updated',
#                                  html=settings.EMAIL_HTML_TEMPLATE.format(
#                                      'The editor %s updated the app, please re-check' % obj.editor,
#                                      obj.prj_code, obj.app_name.encode('utf8'), obj.bundle_id_prefix + obj.bundle_id_suffix,
#                                      obj.app_id, obj.notes),
#                                  to=[i[1] for i in settings.MANAGERS])
                else:
                    print 'seding email to editor...'
                    Notice.objects.send_notice('New App Registration <font color="red">Needs Check</font>',
                        '''
                        <p>Your app registration needs check and update:</p>
                        <p>App Code: <font color='red'>{0}</font></p>
                        <p>App Name: <font color='red'>{1}</font></p>
                        <p>Full Bundle ID: <font color='red'>{2}</font></p>
                        <p>Notes: <font color='red'>{3}</font></p>
                        '''.format(obj.prj_code, obj.app_name.encode('utf8'), obj.get_full_bundle_id(),
                                   obj.notes),
                        obj.editor)
#                    email_sending(subject='PTS New App Registration Needs Check',
#                                  html=settings.EMAIL_HTML_TEMPLATE.format(
#                                      'Your app registration needs check and update',
#                                      obj.prj_code, obj.app_name.encode('utf8'), obj.get_full_bundle_id(),
#                                      obj.app_id, obj.notes),
#                                  to=[obj.editor])
                obj.save()
            elif obj.status == 'Z':
                rtn = api_call('%s%s' % (settings.PS_DOMAIN, settings.PS_CANCEL_APP),
                    json.dumps({'request': {'product_id': obj.prd_id, 'app_code': obj.prj_code,
                        'status': 'cancel'}}), 'POST', {'Content-Type': 'application/json'})
                if not rtn.get('code') == 1:
                    mail_admins('Cancel App Creation Request Sent Failed', rtn.get('msg'))
                    self.message_user(request, 'Server Error', messages.ERROR)
                    return
#                obj.appleid_set.update(status='C')
                obj.save()
                obj.appversion_set.update(status='C')
                sub_infos = []
                for v in obj.appversion_set.all():
                    sub_info = SubInfo.objects.filter(app=v.app, version=v.code)[:1]
                    if sub_info:
                        sub_infos.append(sub_info[0].request_id)
                self.cancel_sub_info(','.join(sub_infos))
            else:
                obj.save()
        # save extra info
        extra = AppExtraInfo.objects.get_or_create(app=obj)[0]
#        flurry_key = request.REQUEST.get('flurry_key')
        media_local = request.REQUEST.get('media_local')
        media_remote = request.REQUEST.get('media_remote')
        display_name = request.REQUEST.get('display_name')
#        if flurry_key:
#            extra.flurry_key = flurry_key
        if media_local:
            extra.media_local = media_local
        if media_remote:
            extra.media_remote = media_remote
        if display_name:
            extra.display_name = display_name
        if hasattr(obj, 'special'):
            extra.special = obj.special
#        extra.cross_local = request.REQUEST.get('cross_local')
#        extra.cross_remote = request.REQUEST.get('cross_remote')
#        extra.orientation = request.REQUEST.get('orientation')
        extra.save()


class UserGroupAdmin(admin.ModelAdmin):
    list_display = ('name', 'owner', 'get_studios', 'get_production_teams')
    filter_horizontal = ('studios',)
    list_per_page = 20
    form = CustomUserGroupForm

    @field('Production Teams', allow_tags=True)
    def get_production_teams(self, obj):
        return "<br />".join([t.name for t in obj.productionteam_set.all()])

    @field("PJMs", allow_tags=True)
    def get_users(self, obj):
        return "<br />".join([user.username for user in obj.user.all()])

    # @field("Available Studio Clouds", allow_tags=True)
    # def get_clouds(self, obj):
    #     return "<br />".join(obj.clouds.values_list('cloud_id', flat=True))

    @field('Available Studios', allow_tags=True)
    def get_studios(self, obj):
        studios = []
        for c in obj.studios.all():
            studios.append(c)
        studios = sorted(studios, key=lambda s: s.custom_id)
        return "<br />".join([s.__unicode__() for s in studios])

    def get_actions(self, request):
        """
        remove delete action
        """
        actions = super(UserGroupAdmin, self).get_actions(request)
        if actions.get('delete_selected'):
            del actions['delete_selected']
        return actions

    @csrf_protect_m
    @transaction.commit_on_success
    def change_view(self, request, object_id, form_url='', extra_context=None):
        user = request.user
        if user.groups.filter(name='Management').exists() and not user.is_superuser:
            raise PermissionDenied
        return admin.ModelAdmin.change_view(self, request, object_id, form_url=form_url, extra_context=extra_context)


class ProductionTeamAdmin(admin.ModelAdmin):
    list_per_page = 20
    list_display = ('name', 'company', 'division', 'get_user', 'get_studios')
    filter_horizontal = ('user', 'studios')
    form = ProductionTeamForm

    @field('PJMs', allow_tags=True)
    def get_user(self, obj):
        return "<br />".join([u.username for u in obj.user.all()])

    @field('Available Studios', allow_tags=True)
    def get_studios(self, obj):
        return "<br />".join([s.__unicode__() for s in obj.studios.all()])

    def get_actions(self, request):
        """
        remove delete action
        """
        actions = super(ProductionTeamAdmin, self).get_actions(request)
        if actions.get('delete_selected'):
            del actions['delete_selected']
        return actions

    @csrf_protect_m
    @transaction.commit_on_success
    def change_view(self, request, object_id, form_url='', extra_context=None):
        user = request.user
        if user.groups.filter(name='Management').exists() and not user.is_superuser:
            raise PermissionDenied
        return admin.ModelAdmin.change_view(self, request, object_id, form_url=form_url, extra_context=extra_context)


admin.site.register(Studio, StudioAdmin)
admin.site.register(StudioCloud, StudioCloudAdmin)
admin.site.register(App, AppAdmin)
admin.site.register(UserGroup, UserGroupAdmin)
admin.site.register(ProductionTeam, ProductionTeamAdmin)

admin.site.unregister(Group)
admin.site.unregister(User)


class CompanyAdmin(admin.ModelAdmin):
    list_per_page = 20
    list_display = ('name', 'display_name', 'location', 'code')
    form = CompanyForm


class CustomGroupAdmin(GroupAdmin):
    list_display = ('name', 'get_users_list',)
    form = CustomGroupForm

    fieldsets = (
        (None, {
            'fields':
            (
                'name',
                'permissions',
                'company'
            )
        }),
    )

    class Media:
        js = ('base/js/set_group_company.js', )

    @field('Included Users', allow_tags=True)
    def get_users_list(self, obj):
        return '<br />'.join(obj.user_set.values_list('username', flat=True))

    @field('Company', allow_tags=True)
    def get_company(self, obj):
        companygroup = CompanyGroup.objects.filter(group=obj)
        return obj.companygroup.company.display_name if companygroup and companygroup[0] else ' '

    def save_model(self, request, obj, form, change):
        obj.save()
        companygroup = CompanyGroup.objects.get_or_create(group=obj)[0]
        company_req = request.REQUEST.get('company')
        company = Company.objects.get(id=company_req)
        # change group name
        group_name = obj.name.split(' --- ')[1] if ' --- ' in obj.name else obj.name
        name = company.display_name + ' --- ' + group_name
        obj.name = name
        print name
        obj.save()
        companygroup.company = company
        companygroup.save()


class CustomUserAdmin(UserAdmin):
    list_display = ('username', 'email', 'is_active', 'is_staff', 'is_superuser', 'get_roles')

    @field('Role', allow_tags=True)
    def get_roles(self, obj):
        return "<br />".join(obj.groups.values_list('name', flat=True))

admin.site.register(Company, CompanyAdmin)
admin.site.register(Group, CustomGroupAdmin)
admin.site.register(User, CustomUserAdmin)
